home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Python 1.4 / Python 1.4 source / Mac / scripts / MkDistr.py < prev    next >
Encoding:
Python Source  |  1996-10-22  |  6.2 KB  |  282 lines  |  [TEXT/Pyth]

  1. #
  2. # Interactively decide what to distribute
  3. #
  4. #
  5. # The exclude file signals files to always exclude,
  6. # The pattern file lines are of the form
  7. # *.c
  8. # This excludes all files ending in .c.
  9. #
  10. # The include file signals files and directories to include.
  11. # Records are of the form
  12. # ('Tools:bgen:AE:AppleEvents.py', 'Lib:MacToolbox:AppleEvents.py')
  13. # This includes the specified file, putting it in the given place, or
  14. # ('Tools:bgen:AE:AppleEvents.py', None)
  15. # This excludes the specified file.
  16. #
  17. from MkDistr_ui import *
  18. import fnmatch
  19. import regex
  20. import os
  21. import sys
  22. import macfs
  23. import macostools
  24.  
  25. SyntaxError='Include/exclude file syntax error'
  26.  
  27. class Matcher:
  28.     """Include/exclude database, common code"""
  29.     
  30.     def __init__(self, filename):
  31.         self.filename = filename
  32.         self.rawdata = []
  33.         self.parse(filename)
  34.         self.rawdata.sort()
  35.         self.rebuild()
  36.         self.modified = 0
  37.  
  38.     def parse(self, dbfile):
  39.         try:
  40.             fp = open(dbfile)
  41.         except IOError:
  42.             return
  43.         data = fp.readlines()
  44.         fp.close()
  45.         for d in data:
  46.             d = d[:-1]
  47.             if not d or d[0] == '#': continue
  48.             pat = self.parseline(d)
  49.             self.rawdata.append(pat)
  50.                 
  51.     def save(self):
  52.         fp = open(self.filename, 'w')
  53.         self.savedata(fp, self.rawdata)
  54.         self.modified = 0
  55.             
  56.     def add(self, value):
  57.         if len(value) == 1:
  58.             value = value + ('',)
  59.         self.rawdata.append(value)
  60.         self.rebuild1(value)
  61.         self.modified = 1
  62.         
  63.     def delete(self, value):
  64.         key = value
  65.         for i in range(len(self.rawdata)):
  66.             if self.rawdata[i][0] == key:
  67.                 del self.rawdata[i]
  68.                 self.unrebuild1(i, key)
  69.                 self.modified = 1
  70.                 return
  71.         print 'Not found!', key
  72.                 
  73.     def getall(self):
  74.         return map(lambda x: x[0], self.rawdata)
  75.     
  76.     def get(self, value):
  77.         for src, dst in self.rawdata:
  78.             if src == value:
  79.                 return src, dst
  80.         print 'Not found!', value
  81.                 
  82.     def is_modified(self):
  83.         return self.modified
  84.                             
  85. class IncMatcher(Matcher):
  86.     """Include filename database and matching engine"""
  87.  
  88.     def rebuild(self):
  89.         self.idict = {}
  90.         self.edict = {}
  91.         for v in self.rawdata:
  92.             self.rebuild1(v)
  93.             
  94.     def parseline(self, line):
  95.         try:
  96.             data = eval(line)
  97.         except:
  98.             raise SyntaxError, line
  99.         if type(data) <> type(()) or len(data) not in (1,2):
  100.             raise SyntaxError, line
  101.         if len(data) == 1:
  102.             data = data + ('',)
  103.         return data
  104.         
  105.     def savedata(self, fp, data):
  106.         for d in self.rawdata:
  107.             fp.write(`d`+'\n')
  108.         
  109.     def rebuild1(self, (src, dst)):
  110.         if dst == '':
  111.             dst = src
  112.         if dst == None:
  113.             self.edict[src] = None
  114.         else:
  115.             self.idict[src] = dst
  116.             
  117.     def unrebuild1(self, num, src):
  118.         if self.idict.has_key(src):
  119.             del self.idict[src]
  120.         else:
  121.             del self.edict[src]
  122.     
  123.     def match(self, patharg):
  124.         removed = []
  125.         # First check the include directory
  126.         path = patharg
  127.         while 1:
  128.             if self.idict.has_key(path):
  129.                 # We know of this path (or initial piece of path)
  130.                 dstpath = self.idict[path]
  131.                 # We do want it distributed. Tack on the tail.
  132.                 while removed:
  133.                     dstpath = os.path.join(dstpath, removed[0])
  134.                     removed = removed[1:]
  135.                 # Finally, if the resultant string ends in a separator
  136.                 # tack on our input filename
  137.                 if dstpath[-1] == os.sep:
  138.                     dir, file = os.path.split(path)
  139.                     dstpath = os.path.join(dstpath, file)
  140.                 return dstpath
  141.             path, lastcomp = os.path.split(path)
  142.             if not path:
  143.                 break
  144.             removed[0:0] = [lastcomp]
  145.         # Next check the exclude directory
  146.         path = patharg
  147.         while 1:
  148.             if self.edict.has_key(path):
  149.                 return ''
  150.             path, lastcomp = os.path.split(path)
  151.             if not path:
  152.                 break
  153.             removed[0:0] = [lastcomp]
  154.         return None
  155.             
  156.     def checksourcetree(self):
  157.         rv = []
  158.         for name in self.idict.keys():
  159.             if not os.path.exists(name):
  160.                 rv.append(name)
  161.         return rv
  162.                 
  163. class ExcMatcher(Matcher):
  164.     """Exclude pattern database and matching engine"""
  165.  
  166.     def rebuild(self):
  167.         self.relist = []
  168.         for v in self.rawdata:
  169.             self.rebuild1(v)
  170.         
  171.     def parseline(self, data):
  172.         return (data, None)
  173.  
  174.     def savedata(self, fp, data):
  175.         for d in self.rawdata:
  176.             fp.write(d[0]+'\n')        
  177.         
  178.     def rebuild1(self, (src, dst)):
  179.         pat = fnmatch.translate(src)
  180.         self.relist.append(regex.compile(pat))
  181.         
  182.     def unrebuild1(self, num, src):
  183.         del self.relist[num]
  184.     
  185.     def match(self, path):
  186.         comps = os.path.split(path)
  187.         file = comps[-1]
  188.         for pat in self.relist:
  189.             if pat and pat.match(file) == len(file):
  190.                 return 1
  191.         return 0        
  192.          
  193.         
  194. class Main:
  195.     """The main program glueing it all together"""
  196.     
  197.     def __init__(self):
  198.         InitUI()
  199.         fss, ok = macfs.GetDirectory('Source directory:')
  200.         if not ok:
  201.             sys.exit(0)
  202.         os.chdir(fss.as_pathname())
  203.         if not os.path.isdir(':Mac:Distributions'):
  204.             os.mkdir(':Mac:Distributions')
  205.         typedist = GetType()
  206.         self.inc = IncMatcher(':Mac:Distributions:%s.include'%typedist)
  207.         self.exc = ExcMatcher(':Mac:Distributions:%s.exclude'%typedist)
  208.         self.ui = MkDistrUI(self)
  209.         self.ui.mainloop()
  210.         
  211.     def check(self):
  212.         return self.checkdir(':', 1)
  213.         
  214.     def checkdir(self, path, istop):
  215.         files = os.listdir(path)
  216.         rv = []
  217.         todo = []
  218.         for f in files:
  219.             if self.exc.match(f):
  220.                 continue
  221.             fullname = os.path.join(path, f)
  222.             if self.inc.match(fullname) == None:
  223.                 if os.path.isdir(fullname):
  224.                     todo.append(fullname)
  225.                 else:
  226.                     rv.append(fullname)
  227.         for d in todo:
  228.             if len(rv) > 100:
  229.                 if istop:
  230.                     rv.append('... and more ...')
  231.                 return rv
  232.             rv = rv + self.checkdir(d, 0)
  233.         return rv
  234.         
  235.     def run(self, destprefix):
  236.         missing = self.inc.checksourcetree()
  237.         if missing:
  238.             print '==== Missing source files ===='
  239.             for i in missing:
  240.                 print i
  241.             print '==== Fix and retry ===='
  242.             return
  243.         if not self.rundir(':', destprefix, 0):
  244.             return
  245.         self.rundir(':', destprefix, 1)
  246.  
  247.     def rundir(self, path, destprefix, doit):
  248.         files = os.listdir(path)
  249.         todo = []
  250.         rv = 1
  251.         for f in files:
  252.             if self.exc.match(f):
  253.                 continue
  254.             fullname = os.path.join(path, f)
  255.             if os.path.isdir(fullname):
  256.                 todo.append(fullname)
  257.             else:
  258.                 dest = self.inc.match(fullname)
  259.                 if dest == None:
  260.                     print 'Not yet resolved:', fullname
  261.                     rv = 0
  262.                 if dest:
  263.                     if doit:
  264.                         print 'COPY ', fullname
  265.                         print '  -> ', os.path.join(destprefix, dest)
  266.                         macostools.copy(fullname, os.path.join(destprefix, dest), 1)
  267.         for d in todo:
  268.             if not self.rundir(d, destprefix, doit):
  269.                 rv = 0
  270.         return rv
  271.         
  272.     def save(self):
  273.         self.inc.save()
  274.         self.exc.save()
  275.         
  276.     def is_modified(self):
  277.         return self.inc.is_modified() or self.exc.is_modified()
  278.  
  279. if __name__ == '__main__':
  280.     Main()
  281.     
  282.